/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.bomt.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.comac.ins.bomt.domain.DetailModelStatus;
import com.comac.ins.bomt.domain.DetailStrengthBom;
import com.comac.ins.bomt.domain.vo.DetailModelStatusVo;
import com.comac.ins.bomt.domain.vo.DetailOriginalV2BomVo;
import com.comac.ins.bomt.domain.vo.DetailStandardBomVo;
import com.comac.ins.bomt.domain.vo.DetailStrengthBomImportVo;
import com.comac.ins.bomt.service.BomFileParseService;
import com.comac.ins.common.core.domain.model.LoginUser;
import com.comac.ins.common.biz.exception.BizException;
import com.comac.ins.common.biz.utils.BizAssertUtil;
import com.comac.ins.common.core.utils.MapstructUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @author zhanghongyi
 * @date 2024/8/28
 * @description BomFileParserUtil
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class BomFileParseServiceImpl implements BomFileParseService {
    @Value("${bom.original.headerRowNo:7}")
    private Integer originalBomHeaderRowNo;

    @Value("${bom.codePath.joinChar:,}")
    private String fullCodePathJoinChar;

    /**
     * 解析模型状态清单
     */
    @Override
    public Map<String, List<DetailModelStatus>> parseModelStatus(LoginUser loginUser, MultipartFile file, String aircraftModel, String track) {
        Map<String, List<DetailModelStatus>> result = new HashMap<>(10);
        try (ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream())) {
            ZipEntry zipEntry = zipInputStream.getNextEntry();
            while (zipEntry != null) {
                String groupName = StringUtils.split(zipEntry.getName(), ".")[0];
                if (!zipEntry.isDirectory()) {
                    List<DetailModelStatusVo> parsedItemList = EasyExcel.read(zipInputStream).ignoreEmptyRow(true).excelType(ExcelTypeEnum.CSV).headRowNumber(1).charset(StandardCharsets.UTF_8).head(DetailModelStatusVo.class).autoCloseStream(false).sheet().doReadSync();
                    AtomicLong ord = new AtomicLong();
                    Stack<DetailModelStatusVo> parentStack = new Stack<>();
                    for (DetailModelStatusVo voItem : parsedItemList) {
                        while (CollectionUtils.isNotEmpty(parentStack) && (StringUtils.equals("1", voItem.getLevel()) || !StringUtils.equals("1", parentStack.peek().getLevel()))) {
                            parentStack.pop();
                        }

                        parentStack.push(voItem);
                        voItem.setFullCodePath(StringUtils.join(parentStack.stream().map(DetailModelStatusVo::getCode).toList(), fullCodePathJoinChar));
                        voItem.setOrd(ord.getAndIncrement());
                    }
                    List<DetailModelStatus> modelList = parsedItemList.stream().map(item -> MapstructUtils.convert(item, DetailModelStatus.class)).toList();
                    modelList.forEach(item -> {
                        item.setAircraftModel(aircraftModel);
                        item.setGroupType(groupName);
                        item.setTrack(track);
                    });
                    result.put(groupName, modelList);
                }
                zipEntry = zipInputStream.getNextEntry();
            }
            zipInputStream.closeEntry();
        } catch (IOException e) {
            throw new BizException(MessageFormat.format("parse model status fail:{0}", e.getMessage()));
        }
        return result;
    }

    /**
     * 解析原始装机清单
     */
    @Override
    public List<DetailOriginalV2BomVo> parseOrigin(MultipartFile file) {
        try {
            List<DetailOriginalV2BomVo> parseResult = EasyExcel.read(file.getInputStream()).headRowNumber(originalBomHeaderRowNo).head(DetailOriginalV2BomVo.class).autoCloseStream(false).sheet().doReadSync();
            BizAssertUtil.isFalse(CollectionUtils.isEmpty(parseResult) ||
                StringUtils.isBlank(parseResult.get(0).getName()) ||
                StringUtils.isBlank(parseResult.get(0).getLevel()) ||
                StringUtils.isBlank(parseResult.get(0).getCnt()) ||
                StringUtils.isBlank(parseResult.get(0).getSection()) ||
                StringUtils.isBlank(parseResult.get(0).getVersion()) ||
                StringUtils.isBlank(parseResult.get(0).getCode()), "please check original bom xlsx is right");
            Stack<DetailOriginalV2BomVo> parentStack = new Stack<>();
            AtomicLong ord = new AtomicLong();
            for (DetailOriginalV2BomVo detailOriginalV2BomVo : parseResult) {
                if (CollectionUtils.isNotEmpty(parentStack) && Integer.parseInt(detailOriginalV2BomVo.getLevel()) <= Integer.parseInt(parentStack.peek().getLevel())) {
                    int curLevel = Integer.parseInt(detailOriginalV2BomVo.getLevel());
                    while (CollectionUtils.isNotEmpty(parentStack) && Integer.parseInt(parentStack.peek().getLevel()) >= curLevel) {
                        parentStack.pop();
                    }
                }
                parentStack.push(detailOriginalV2BomVo);
                String fullCodePath = StringUtils.join(parentStack.stream().map(DetailOriginalV2BomVo::getCode).toList(), fullCodePathJoinChar);
                detailOriginalV2BomVo.setOrd(ord.getAndIncrement());
                detailOriginalV2BomVo.setFullCodePath(fullCodePath);
            }
            return parseResult;
        } catch (IOException e) {
            log.error(MessageFormat.format("parse bom file {0} fail", file.getOriginalFilename()), e);
            throw new BizException("parse bom file fail");
        }
    }

    /**
     * 解析标准装机清单
     */
    @Override
    public Map<String, List<DetailStandardBomVo>> parseStandard(LoginUser loginUser, MultipartFile file, String aircraftModel, String track) {
        Map<String, List<DetailStandardBomVo>> result = new HashMap<>();
        try (ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream(), Charset.forName("GBK"))) {
            ZipEntry zipEntry = zipInputStream.getNextEntry();
            while (zipEntry != null) {
                String fileName = StringUtils.split(zipEntry.getName(), ".")[0];
                String[] tokes = StringUtils.split(fileName, "_");
                BizAssertUtil.isTrue(tokes.length == 3, "parse file name fail，check file name like 'C919_S50_标准装机清单.xlsx'");
                if (!zipEntry.isDirectory() && StringUtils.equals(tokes[2], "标准装机清单")) {
                    List<DetailStandardBomVo> parsedItemList = EasyExcel.read(zipInputStream).ignoreEmptyRow(true).excelType(ExcelTypeEnum.XLSX).headRowNumber(1).charset(StandardCharsets.UTF_8).head(DetailStandardBomVo.class).autoCloseStream(false).sheet().doReadSync();
                    AtomicLong ord = new AtomicLong();
                    Stack<DetailStandardBomVo> parentStack = new Stack<>();


                    for (DetailStandardBomVo voItem : parsedItemList) {

                        if (CollectionUtils.isNotEmpty(parentStack) && Integer.parseInt(voItem.getLevel()) <= Integer.parseInt(parentStack.peek().getLevel())) {
                            int curLevel = Integer.parseInt(voItem.getLevel());
                            while (CollectionUtils.isNotEmpty(parentStack) && Integer.parseInt(parentStack.peek().getLevel()) >= curLevel) {
                                parentStack.pop();
                            }
                        }
                        parentStack.push(voItem);
                        voItem.setFullCodePath(StringUtils.join(parentStack.stream().map(DetailStandardBomVo::getCode).toList(), fullCodePathJoinChar));
                        voItem.setOrd(ord.getAndIncrement());
                        voItem.setAircraftModel(aircraftModel);
                        voItem.setGroupType(tokes[1]);
                        voItem.setTrack(track);
                    }
                    result.put(tokes[1], parsedItemList);
                }
                zipEntry = zipInputStream.getNextEntry();
            }
            zipInputStream.closeEntry();
        } catch (IOException e) {
            throw new BizException(MessageFormat.format("parse standard bom fail:{0}", e.getMessage()));
        }
        return result;
    }

    /**
     * 解析强度数模清单
     */
    @Override
    public Map<String, List<DetailStrengthBom>> parseStrength(LoginUser loginUser, MultipartFile file, String aircraftModel, String track) {
        Map<String, List<DetailStrengthBom>> result = new HashMap<>(10);
        try (ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream(), Charset.forName("GBK"))) {
            ZipEntry zipEntry = zipInputStream.getNextEntry();
            while (zipEntry != null) {
                String fileName = StringUtils.split(zipEntry.getName(), ".")[0];
                String[] tokes = StringUtils.split(fileName, "_");
                BizAssertUtil.isTrue(tokes.length == 3, "parse file name fail，check file name like 'C919_S50_强度数模清单.xlsx'");
                if (!zipEntry.isDirectory() && StringUtils.equals(tokes[2], "强度数模清单")) {
                    List<DetailStrengthBomImportVo> parsedItemList = EasyExcel.read(zipInputStream).ignoreEmptyRow(true).excelType(ExcelTypeEnum.XLSX).headRowNumber(1).charset(StandardCharsets.UTF_8).head(DetailStrengthBomImportVo.class).autoCloseStream(false).sheet().doReadSync();
                    AtomicLong ord = new AtomicLong();
                    Stack<DetailStrengthBomImportVo> parentStack = new Stack<>();

                    List<DetailStrengthBom> modelList = new ArrayList<>();
                    for (DetailStrengthBomImportVo voItem : parsedItemList) {
                        while (CollectionUtils.isNotEmpty(parentStack) && (StringUtils.equals("1", voItem.getLevel()) || !StringUtils.equals("1", parentStack.peek().getLevel()))) {
                            parentStack.pop();
                        }
                        parentStack.push(voItem);
                        DetailStrengthBom qbom = new DetailStrengthBom();
                        modelList.add(qbom);
                        BeanUtils.copyProperties(voItem, qbom);
                        qbom.setFullCodePath(StringUtils.join(parentStack.stream().map(DetailStrengthBomImportVo::getCode).toList(), fullCodePathJoinChar));
                        qbom.setOrd(ord.getAndIncrement());
                        qbom.setAircraftModel(aircraftModel);
                        qbom.setGroupType(tokes[1]);
                        qbom.setTrack(track);
                        Pair<String, String> versionAndNum = voItem.getVersionAndNum();
                        qbom.setVersionNum(versionAndNum.getRight());
                        qbom.setVersion(versionAndNum.getLeft());
                    }
                    result.put(tokes[1], modelList);
                }
                zipEntry = zipInputStream.getNextEntry();
            }
            zipInputStream.closeEntry();
        } catch (IOException e) {
            throw new BizException(MessageFormat.format("parse strength bom fail:{0}", e.getMessage()));
        }
        return result;
    }
}
